package com.gitee.mall.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.gitee.common.exception.NoStockException;
import com.gitee.common.to.mq.OrderTo;
import com.gitee.common.to.mq.StockDetailTo;
import com.gitee.common.to.mq.StockLockedTo;
import com.gitee.common.utils.R;
import com.gitee.mall.order.entity.OrderEntity;
import com.gitee.mall.ware.feign.OrderFeignService;
import com.gitee.mall.ware.entity.WareOrderTaskDetailEntity;
import com.gitee.mall.ware.entity.WareOrderTaskEntity;
import com.gitee.mall.ware.service.WareOrderTaskDetailService;
import com.gitee.mall.ware.service.WareOrderTaskService;
import com.gitee.mall.ware.vo.OrderItemVo;
import com.gitee.mall.ware.vo.SkuHasStockVo;
import com.gitee.mall.ware.vo.SkuWareHasStock;
import com.gitee.mall.ware.vo.WareSkuLockVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gitee.common.utils.PageUtils;
import com.gitee.common.utils.Query;

import com.gitee.mall.ware.dao.WareSkuDao;
import com.gitee.mall.ware.entity.WareSkuEntity;
import com.gitee.mall.ware.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    private WareOrderTaskService wareOrderTaskService;
    @Autowired
    private WareOrderTaskDetailService wareOrderTaskDetailService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private OrderFeignService orderFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 查询sku是否有库存
     *
     * @param skuIds
     * @return
     */
    @Override
    public List<SkuHasStockVo> getSkusHasStock(List<Long> skuIds) {
        List<SkuHasStockVo> collect = skuIds.stream().map(skuId -> {
            SkuHasStockVo vo = new SkuHasStockVo();

            //查询当前sku的总库存量
            //SELECT SUM(stock-stock_locked) FROM `wms_ware_sku` WHERE sku_id=1
            Long count = baseMapper.getSkuStock(skuId);

            vo.setSkuId(skuId);
            vo.setHasStock(count == null ? false : count > 0);
            return vo;
        }).collect(Collectors.toList());
        return collect;
    }


    /**
     * 锁定库存
     *
     * @param vo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean orderLockStock(WareSkuLockVo vo) {

        //维护库存工作单
        WareOrderTaskEntity wareOrderTask = new WareOrderTaskEntity();
        wareOrderTask.setOrderSn(vo.getOrderSn());
        wareOrderTaskService.save(wareOrderTask);

        //查询sku是否有库存
        List<OrderItemVo> itemVos = vo.getLocks();
        List<SkuWareHasStock> hasStocks = itemVos.stream()
                .map(itemVo -> {
                    //那些仓库有库存
                    SkuWareHasStock hasStock = new SkuWareHasStock();
                    hasStock.setSkuId(itemVo.getSkuId());
                    hasStock.setNum(itemVo.getCount());
                    List<Long> wareIds = baseMapper.listWareIdHasSkuStock(itemVo.getSkuId());
                    hasStock.setWareId(wareIds);
                    return hasStock;
                }).collect(Collectors.toList());


        //锁定库存
        for (SkuWareHasStock hasStock : hasStocks) {            //遍历每一个sku
            boolean lock = false;
            for (Long wareId : hasStock.getWareId()) {          //遍历每一个仓库
                //锁定库存
                int lockSkuStock = baseMapper.lockSkuStock(hasStock.getSkuId(), hasStock.getNum(), wareId);
                if (lockSkuStock == 1) {
                    lock = true;
                    //库存工作单详情
                    WareOrderTaskDetailEntity entity = new WareOrderTaskDetailEntity(null, hasStock.getSkuId(), "", hasStock.getNum(), wareOrderTask.getId(), wareId, 1);
                    wareOrderTaskDetailService.save(entity);

                    //库存锁定成功  可靠消息+最终一致性 延时任务判断支付状态来判断是否释放库存
                    StockDetailTo stockDetailTo = new StockDetailTo();
                    BeanUtils.copyProperties(entity, stockDetailTo);
                    StockLockedTo stockLockedTo = new StockLockedTo(wareOrderTask.getOrderId(), wareOrderTask.getId(), stockDetailTo);
                    rabbitTemplate.convertAndSend("stock-event-exchange", "stock.locked", stockLockedTo);
                    break;
                }
            }

            if (!lock) {                            //库存锁定失败
                throw new NoStockException(hasStock.getSkuId());
            }

        }

        return true;
    }


    /**
     * 延时任务释放库存信息
     *
     * @param to
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void releaseStock(StockLockedTo to) {
        Long orderId = to.getOrderId();
        R r = orderFeignService.oderInfo(orderId);
        if (r.getCode() != 0) {
            throw new RuntimeException("调用订单远程服务失败");
        }

        OrderEntity order = r.getData("order", new TypeReference<OrderEntity>() {
        });
        if (order == null || order.getStatus() == 4) {
            //订单不存在（异常回滚） 或者订单被取消(用户取消)
            //解锁库存
            Long detailId = to.getStockDetailTo().getId();
            WareOrderTaskDetailEntity taskDetail = wareOrderTaskDetailService.getById(detailId);
            if (taskDetail != null && taskDetail.getLockStatus() == 1) {
                //当前库存工作单详情，状态1 已锁定但是未解锁才可以解锁
                unLockStock(taskDetail.getSkuId(), taskDetail.getWareId(), taskDetail.getSkuNum(), detailId);
            }
        }


    }

    /**
     * 超时未支付 从订单队列中转发来的消息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void orderCloseRelease(OrderTo to) {
        WareOrderTaskEntity orderTask = wareOrderTaskService.getOne(new QueryWrapper<WareOrderTaskEntity>().eq("order_id", to.getId()));
        if (orderTask != null) {
            //按照工作单找到所有 没有解锁的库存，进行解锁
            List<WareOrderTaskDetailEntity> entities = wareOrderTaskDetailService.list(
                    new QueryWrapper<WareOrderTaskDetailEntity>()
                            .eq("task_id", orderTask.getId())
                            .eq("lock_status", 1));
            for (WareOrderTaskDetailEntity taskDetail : entities) {
                if (taskDetail != null && taskDetail.getLockStatus() == 1) {
                    //当前库存工作单详情，状态1 已锁定但是未解锁才可以解锁
                    unLockStock(taskDetail.getSkuId(), taskDetail.getWareId(), taskDetail.getSkuNum(), taskDetail.getId());
                }
            }
        }
    }

    /**
     * 释放库存  修改库存工作单
     *
     * @param skuId    skuId
     * @param wareId   库存id
     * @param skuNum   锁定数量
     * @param detailId 工作单详情id
     */
    private void unLockStock(Long skuId, Long wareId, Integer skuNum, Long detailId) {

        //库存解锁(恢复库存)
        baseMapper.unlockStock(skuId, wareId, skuNum);
        //更新库存工作单的状态
        WareOrderTaskDetailEntity entity = new WareOrderTaskDetailEntity();
        entity.setId(detailId);
        entity.setLockStatus(2);//变为已解锁
        wareOrderTaskDetailService.updateById(entity);
    }
}